using System;
using System.Collections.Generic;
using System.Text;

using Mono.Cecil;
using Mono.Cecil.Cil;

using CILDiffLibPrime.Attributes;

namespace CILDiffLibPrime
{
    public class PackageBinary
    {
        CecilFriendlyCustomAttributes m_attributes=null;
        public PackageBinary()
        {
           m_attributes = new CecilFriendlyCustomAttributes("CILDiffLibPrime.dll");
        }

        const int NEW=0;
        const int MODIFIED = 1;
        const int DELETED = 2;
        const int SIGNATURE = 3;

        internal void PackageNewClasses(AssemblyDefinition ad, List<TypeDefinition> list)
        {
            foreach (TypeDefinition md in list)
            {
                //m_attributes.SetClassAttribute(ad, md, NEW, "");
            }
        }

        internal void PackageDeletedClasses(AssemblyDefinition ad, List<TypeDefinition> list)
        {
            foreach (TypeDefinition td in list)
            {
                TypeDefinition tdCopy = td.Clone();
                tdCopy.Name += "_deleted";
                //m_attributes.SetClassAttribute(ad, tdCopy, DELETED, "");
                ad.MainModule.Inject(tdCopy);
            }
        }


        public void PackageNewMethods( AssemblyDefinition ad, List<MethodDefinition> newMethods )
        {
            foreach (MethodDefinition md in newMethods)
            {
               //m_attributes.SetMethodAttribute(ad, md, NEW, "");
            }
        }

        public void PackageDeletedMethods( AssemblyDefinition ad, TypeDefinition type, List<MethodDefinition> deletedMethods)
        {
            foreach (MethodDefinition md in deletedMethods)
            {
                MethodDefinition mdCopy = md.Clone();
                mdCopy.Name += "_deleted";
                //m_attributes.SetMethodAttribute(ad, mdCopy, DELETED, "");
                ad.MainModule.Inject(mdCopy, type);
            }
            //Import the modified type into the AssemblyDefinition.
            ad.MainModule.Import(type);
        }

        public void PackageModifiedMethod(MethodDefinition md_before, MethodDefinition md_after,
            TypeDefinition type, AssemblyDefinition ad, SectionChange signature,
            SectionChange body, SectionChange returnType, SectionChange attributes,
            SectionChange properties, SectionChange overrides, SectionChange parameters,
            SectionChange genericParameters, SectionChange customAttributes)
        {
            MethodDefinition mdCopy = md_before.Clone();
            mdCopy.Name += "_before";
            ad.MainModule.Inject(mdCopy, type);

            m_attributes.SetMethodAttribute(ad, md_after, signature, body, returnType, attributes,
                properties, overrides, parameters, genericParameters, customAttributes);

            // Outside ...
            //Import the modified type into the AssemblyDefinition.
            ad.MainModule.Import(type);
        }

        private void MergeInstructions(MethodDefinition md_before, MethodDefinition md_after, Diff.Item[] items)
        {
            MethodDefinition newMd = md_after.Clone();
            List<Instruction> instructions = new List<Instruction>();
            foreach (Diff.Item item in items)
            {
                //md_before.Body.Instructions[diff];
                //md_after.Body.Instructions[diff];

                int delA = item.deletedA;
                int addB = item.insertedB;
                int starta = item.StartA;
                int startb = item.StartB;
                if (delA > 0 && addB > 0)
                {
                    // Change
                    Console.Write("before:" + md_before.Body.Instructions[starta]);
                    Console.Write("after:" + md_after.Body.Instructions[startb]);
                }
                else if (delA > 0 && addB == 0)
                {
                    Console.Write("-:" + md_before.Body.Instructions[starta]);
                }
                else if (addB > 0 && delA == 0)
                {
                    Console.Write("+:" + md_after.Body.Instructions[startb]);
                }
            }
        }
    }
}